Fortran入门教程(七) 您所在的位置:网站首页 fortran module用法 Fortran入门教程(七)

Fortran入门教程(七)

#Fortran入门教程(七)| 来源: 网络整理| 查看: 265

数组

在之前的章节中,常量,变量用于保存一个数值。如果需要保存大量的数据,就可以用到数组,数组是一系列相同类型的数据组合而成的特殊数据类型。

1. 数组的声明

在创建数组时,可以增加dimension修饰词来表明声明数组的长度,也可以在变量名称后增加圆括号,并在圆括号内使用数字来表明数组的长度。下面的两个例子都声明了一个用于储存integer变量类型的长度为10的数组。

integer, dimension(10) :: array integer :: array(10)

总的来说,按照如下的方式声明数组:

DataType, dimension(size) :: name DataType :: array(size)

如果需要声明多维数组,使用逗号分隔各个纬度

integer, dimension(10, 10) :: array integer :: array(10, 10)

在声明时,也可以使用常量来声明数组的长度,如:

integer, parameter :: n = 10 integer :: array(n)

如果使用变量,则会报错

integer :: n = 10 integer :: array(n)

错误如下:

Error: Explicit shaped array with nonconstant bounds at (1)

默认情况下,数组是从下标1开始索引的,但是可以在声明时改变开始索引的数字,如

intger :: a(-3:3)

该数组大小为7,索引从-3到3。

2. 数组的赋值 2.1 整体赋值 显式赋值

使用/(和/)或者[ 和]将需要赋予的数据括起来,用=号赋给声明时的数组。

integer :: array(5) = (/ 1, 2, 3, 4, 5 /) integer :: array(5) = [1, 2, 3, 4, 5]

赋值后数组五个数分别为1, 2, 3, 4, 5.

注:括号和斜杠之间不能用空格

隐式赋值 integer :: i integer :: array(5) = (/ (i, i = 1, 5)/)

隐式赋值相当于省略了do的内容,原本可以用do循环写成如下形式

integer :: array(5), i do i = 1, 5 array(i) = i end do

隐式循环也可以嵌套, 如

integer :: i, j integer :: array(4) =(/ ((i + j, i = 1, 2), j = 1, 2) /)

注: 整体赋值时,给定值的数量必须与数组声明的数量相同,不然会报错,比如

integer :: a(5) = (/1, 2, 3/)

会报错,因为数组长度为5,而只给了3个初值。 如果需要赋满,可以改成这样

integer :: i integer :: a(5) = (/ 1, (2, i=1, 3), 3 /) 3. 数组操作 3.1 元素操作

数组声明后直接通过括号 + 索引值来获取数组索引值位置的元素。如

a(1), a(2), a(5)

下面的例程序展示了通过循环读入并且输出一个数组。

!> program 8-1 program read_write_array implicit none integer, parameter :: n = 5 integer :: i integer :: array(n) write(*, "('Enter', I4, ' line, each line with an integer')") n do i = 1, n read(*, *) array(i) end do do i = 1, n write(*, *) array(i) end do end program

在高维数组中, 从纬度低

3.2 数组操作 1. 整体赋值

将数组所有元素赋值为0.

a = 0

将数组赋值为 1, 2, 3

a = [1, 2, 3] a = (/ 1, 2, 3 /)

另数组中所有元素与另一个数组相同,两个数组必须大小相同

a = b 2.基本运算

加减乘除, a, b, c必须大小相同

a = b + c a = b - c a = b * c a = b / c

逻辑运算,a, b, c必须大小相同。对于每一个位置,如果该位置上b == c则将该位置赋值为.true.否则为.false.

a = b == c

上述代码用循环可以表达为

integer, parameter :: n = 10 logical :: a(10) integer :: b(10), c(10), i do i = 1, n a(i) = b(i) == c(i) end do 3. 切片 a(head: tail: step)

该方式将会引用数组索引从head到tail每间隔step步长的所有元素提取出来操作。

如将数组索引3-5的元素都赋值为0

a(3:5) = 0

数组索引3以后的元素赋值为0

a(3:) = 0

将数组中偶数索引设置为0

a(2::2) = 0

将数组翻转

a(1:n) = a(n:1:-1)

假设 b(5,5), a(5), 将a中所有元素赋值为b第二行所有元素

a(:) = b(:, 2) 4. Where

where 语句是一种特殊的数组操作语句,会根据数组的坐标值按照给定的规则进行操作。 where 支持并行运算,比do语句执行快。

如: 将a中所有大于3的元素赋给b中相应的位置

where(a > 3) b = a end where

该操作相当于

do i = 1, n if (a(i) > 3) b(i) = a(i) end do

或是将a中小于60的数赋值为60

where (a < 60) a = 60 end where

相当于

do i = 1, n if (a(i) < 60) a(i) = 60 end do

where 语句中指定的数组可以进行切片,如

where(a(1:3) < 60) a = 60 end where

where语句也可以像if语句一样出现分支结构 比如将所有大于1的设置为1,小于-1的设置为-1,其他不变。

where(a < -1) a = -1 else where(a > 1) a = 1 else where a = a end where

where还可以进行嵌套, 也可以取名, 但是取名的where在结束时需要加上其名字,如

where(a < 5) where(a /= 2) b = 3 else where b = 1 end where end where 5. FORALL

forall 语句可以看作隐式循环的拓展,除了可以实现隐式循环的赋值效果,也可以使用条件判断,语法模型如下

forall (triplet1[, triplet2[, triplet3...]], mask)

triplet是用于赋值的数组坐标范围, mask为条件判断值,只有mask成立才会运行forall中的语句。 如:

forall(i=2:10:2, j=1:5) a(i, j) = i + j end forall

也可以通过mask条件,只处理i == j时

forall(i=1:5, j=1:5, i == j) a(i, j) = i + 1 end forall

或是将a中大于10的赋值为0

forall(i=1:5, j=1:5, a(i, j) > 10) a(i, j) = 0 end forall

forall也可以进行嵌套或与where语句连用,不再赘述。

总的来说, forall 和 where 语句可以缩减代码的编写量, 加快程序的运算速度,但是没有do语句灵活。

4. 数组存储方式

在计算机内存中, fortran二维数组是一列一列存储的, 这意味着内存中a(1:1)会与a(2:1)相邻, 而不与a(1:2)相临。

在多维数组中,数组是逐纬度存储的.

比如数组array(3, 2),在内存空间中依次为

array(1, 1), array(2, 1), array(3, 1), array(1, 2), array(2, 2), array(3, 2) 5. 可变大小数组

在很多情况下,要等到程序执行之后才可以知道需要需要申请多大大小的数组,fortran提供了一类可变大小的数组。该类数组用allocatable修饰词修饰,并且使用:指示数组的纬度。 比如声明一个整数类型的一纬可变数组:

integer, allocatable :: array(:)

如果要申请n纬可变数组, 则需要几个纬度就使用几个冒号。如三位数组: integer, allocatable :: array(:, :)

可变数组在使用之前必须通过allocate函数来声明其内存空间, 如下:

allocate(array(10))

该函数还可以传入stat参数来检查是否成功申请到内存,如:

integer :: err integer, allocatable :: array(:) allocate(array, stat=err) if (err /= 0) print *, "array: Allocation request denied"

allocated 另外, fortran 还提供了 allocated函数来检查一个可变数组是否已经申请到内存。 如:

if (allocated(array)) then print *, "array: Allocated" else print *, "array: Not allocate." end if

deallocate fortran 提供了 dellocate函数来释放申请的内存空间,基本用法如下。

if (allocated(array)) deallocate(array, stat=err) if (err /= 0) print *, "array: Deallocation request denied"

必须是申请内存后的可变数组才可以被deallocate释放。

使用allocate申请的内存空间在程序结束前不会被系统自动释放,如果需要allocate大量空间, 注意及时使用deallocate释放。

下面的程序示例根据用户输入的学生数申请学生名称数组, 读入并且输出学生姓名。

!> program 8-2 program demo_allocate implicit none !> The maximum size of one student's name integer, parameter :: name_max_size = 20 !> Normal variales integer :: student_number, err, i character(len=20), allocatable :: student_names(:) write(*, "('Please enter the number of students', /, '>>> ', $)") read (*, *) student_number !> Allocate `student_names` array allocate(student_names(student_number), stat=err) if (err /= 0) print *, "student_names: Allocation request denied." !> Read all student names do i = 1, student_number write(*, "('Enter the ', I0,'th student''s name', /, '>>> ', $)") i read(*, *) student_names(i) end do !> Output all names write(*, *) "Each name of your student:" do i = 1, student_number write(*, "(I0,' th student''s name is: ', A)") i, student_names(i) end do !> Dellocate `student_names` array if (allocated(student_names)) deallocate(student_names, stat=err) if (err /= 0) print *, "student_names: Deallocation request denied." end program

示例输入输出如下:

Please enter the number of students >>> 5 Enter the 1th student's name >>> A Enter the 2th student's name >>> B Enter the 3th student's name >>> C Enter the 4th student's name >>> D Enter the 5th student's name >>> E Each name of your student: 1 th student's name is: A 2 th student's name is: B 3 th student's name is: C 4 th student's name is: D 5 th student's name is: E


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有